home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 6: Level 6 / 17 Bit - Level 6 (1998)(Epic Marketing)[!].iso / quartz / q0885.dms / q0885.adf / Rexx / GHBackup.rexx < prev    next >
OS/2 REXX Batch file  |  1997-04-10  |  18KB  |  544 lines

  1. /*********************************************************************
  2. GHBackup.rexx - Glenn Holliday's Automated Backup
  3.  
  4. AREXX program to run MRBackup for incremental backups.
  5.  
  6. Calling template:
  7.  
  8.     rx GHBackup [homePath [backupPath [lastFullBackupDate]]]
  9.  
  10. Description:
  11.  
  12.     This program can easily be adapted to your own set of backup
  13. rules.  You _do_ want to examine the code and tweak it, so it
  14. runs on the schedule you want to use for your personal backup
  15. policy.  Note in particular that most people will want to replace
  16. my own scheme for daily backups.  You'll likely either ignore dailies
  17. (you wouldn't do that, would you? :-) or set the parameters to format
  18. a new disk just like I have it doing for a weekly backup.
  19.  
  20. (Note: I've tagged some areas that are candidates for customization
  21.        with *** CUSTOMIZE *** - MRR.)
  22.  
  23. This software is completely public domain.
  24.  
  25. Author:
  26. -- 
  27. Glenn       | ...!uunet!anagld!dahlgren!glenn      (UUCP)
  28. Holliday    | glenn@dahlgren.sed.csc.com           (fully domained)
  29. October 1 1994
  30.  
  31.     Since it's small, the complete software engineering document
  32. set follows.  I thought this might be interesting, it's the easiest
  33. way to explain what backup policies are and how I approached them,
  34. and it may answer questions of the form "why in the world is _that_
  35. in the code?"  Feel free to strip out this part if you wish:
  36.  
  37.     Problem analysis:
  38.  
  39.     Implement a set of rules to do incremental backups.
  40. Recognize daily, weekly, and monthly backups as different cases.
  41. Automatically run MRBackup and set up its parameters for each case.
  42.  
  43.     Backup rules:
  44.  
  45.     Keep a full backup set, a monthly backup set, a weekly
  46. backup set, and six daily backup sets (one for each day between
  47. weekly backups).  Backup every day.
  48.  
  49.     Assume that full backups (the entire disk) are done by hand
  50. when needed.  On the first day of a month, backup all files changed
  51. since the date of the most recent full backup.  On the first day of
  52. a week (Sunday), backup all files changed since the date of the most
  53. recent monthly backup.  On any other day, backup all files whose
  54. archive bits are clear (these are all files changed since the last
  55. backup).  On every backup, set the archive bits of all files backed
  56. up.
  57.  
  58.     Monthly and weekly backups are done to a set of diskettes.
  59. Daily backups (assuming a small amount of change each day) are done to
  60. subdirectories of a single diskette, named for each day.
  61.  
  62.     This program assumes that you keep a record of the date
  63. on which the most recent full backup was done.  It does not provide
  64. for making a full backup, or for storing that date.  Some interesting
  65. extensions could help out with that chore.  I do full backups whenever
  66. my set of monthly backup floppies overflows a box full, store the date
  67. in a file in s:, and have my "backupifold" script supply that date
  68. when it calls GHBackup.rexx.
  69.  
  70.     Design to automate the backup rules:
  71.  
  72. Run mrbackup.rexx daily.  In this program,
  73. Get the current date, day of week,
  74.         date of last monthly backup, and
  75.         date of last full backup.
  76. Classify current date as new month, new week, or ordinary day.
  77. (This partitions the set of all dates into equivalence
  78.  classes, where each equivalence class is identified by
  79.  one of the values of a data type with three possible values.)
  80. If the current date is:
  81.    new month,
  82.    new week,
  83.    ordinary day
  84. Run MRBackup with the selected parameters.
  85.  
  86.     Implementation:
  87.  
  88.     GHBackup.rexx is run daily by some other mechanism.  If you
  89. leave your system on all the time, you probably want to put an entry
  90. in your crontab to run it at the same time each day.  I turn my
  91. system off overnight, so I have cron run a program called "backupifold"
  92. several times a day.  It checks a timestamp of the last backup, and
  93. runs GHBackup.rexx if the timestamp is more than a day old.  I did not
  94. include this program because it uses some shenaigans I don't like to
  95. recogize elapsed time.  If I ever get around to writing the more
  96. elegant solution I have in mind, I'll give it away.
  97.  
  98.     Input arguments:
  99.  
  100.     If any of these are absent, GHBackup.rexx uses defaults.  The
  101. defaults are declared as ARexx variables at the beginning of the
  102. code.
  103.  
  104.      arg                 description                           default
  105.  
  106.      homePath            String, name of disk or other         DH1:
  107.                          filepath to the disk area to be
  108.                          backed up
  109.  
  110.      backupPath          String, filepath to the backup        DF0:
  111.                          medium or directory
  112.  
  113.      lastFullBackupDate  String, date in AmigaDOS format       Jan 1 1978
  114.                          on which the last full backup
  115.                          was done.
  116.  
  117.     This program follows the design outline, using several
  118. functions for modularity.  The outline of the code is as follows:
  119.  
  120. date = date()
  121. classifydate(date) 
  122. select
  123.    newmonth
  124.       setNewMonth()
  125.    newweek
  126.       setNewWeek()
  127.    daily
  128.       setNewDay()
  129. end of program
  130.  
  131. classifydate(date)
  132.    parse date to get day, month, year, day of week
  133.    if day is 1, classify as newmonth
  134.    else if day of week is Sunday, classify as newweek
  135.    else classify as daily
  136.    return classification
  137. setNewMonth():
  138.    (Back up everything since last full backup)
  139.    build "files since" date of last full backup,
  140.    select df0:, AmigaDos, quick format, ignore archive bits,
  141.    and no compression
  142. setNewWeek():
  143.    (Back up everything since last monthly backup.
  144.     Assume date of last monthly backup is the first of the month)
  145.    build "files since" first day of current month,
  146.    select df0:, AmigaDos, quick format, ignore archive bits,
  147.    and no compression
  148. setNewDay():
  149.    (Backup up everything since most recent backup.
  150.     Assume that's everything since archive bits were last set,
  151.     = everything with archive bits clear)
  152.    build backup path, AmigaDos, no format, test archive bits,
  153.    and 16 bit compression
  154. *********************************************************************/
  155.  
  156. /********************
  157. body of ARexx program
  158. ********************/
  159.  
  160. /*******************************************
  161. During debugging, want to see all the errors
  162. *******************************************/
  163. /* TRACE INTERMEDIATE */
  164. signal on ERROR
  165. signal on BREAK_C
  166.  
  167. options results
  168.  
  169. /*** CUSTOMIZE ***/
  170. defaultHomePath = "DH1:"
  171. defaultBackupPath = "DF0:"
  172. defaultLastFullBackup="01-Jan-78 00:00:00"
  173.  
  174. ARG homepath  backuppath lastFullBackup
  175.  
  176. if homepath = '' then
  177.    homepath = defaultHomePath
  178.  
  179. if backuppath = '' then
  180.    backuppath = defaultBackupPath
  181.  
  182. if lastFullBackup = '' then
  183.    lastFullBackup = defaultLastFullBackup
  184.  
  185. /****************************************************************
  186. Arexx parsing has the nasty habit of leaving the leading space on
  187. the last of a string of arguments that it parses from a command
  188. line.  There are code-intensive ways of checking and cleaning up
  189. all the arguments.  Since I know it'll only be a problem on the
  190. last one, here's a cheap way of cleaning it up.
  191. ****************************************************************/
  192.  
  193. lastFullBackup = strip(lastFullBackup)
  194.  
  195. /***************************************
  196. Be sure MRBackup is running.  Assume
  197. only one copy needed, always address the
  198. first MRBackup Rexx port.
  199. startMacro(port, program) is a standard
  200. Rexx macro that, if its first argument
  201. is not already there, runs its second
  202. argument and waits for its first
  203. argument to appear.
  204. ***************************************/
  205. toReturn = startServer('MRBackup_#1', 'mrbackup:mrbackup')
  206. address 'MRBackup_#1'
  207. takecontrol
  208. poptofront
  209.  
  210. /***************************************
  211. Get date, including weekday.
  212. ***************************************/
  213. date      = date('normal')
  214. weekday   = date('weekday')
  215.  
  216. /**********************************************
  217. returns dateclass = newmonth, newweek, or daily
  218. **********************************************/
  219. dateclass = classifydate(date, weekday)
  220.  
  221. /***************************************
  222. send ARexx commands to set MRBackup
  223. parameters for the type of date
  224. ***************************************/
  225. select
  226.    when dateclass = 'newmonth' then
  227.       toReturn = setNewMonth(homepath, backuppath, lastFullBackup)
  228.    when dateclass = 'newweek' then
  229.       toReturn = setNewWeek(homepath, backuppath, date)
  230.    when dateclass = 'daily' then
  231.       toReturn = setNewDaily(homepath, backuppath, weekday)
  232.    otherwise
  233.       do
  234.          Say 'unrecognized date type ' || dateclass
  235.          toReturn = 'FAIL'
  236.          error /* Use error: function to exit */
  237.       end
  238. end
  239.  
  240. /***************
  241. Start the backup
  242. ***************/
  243.  
  244. if toReturn = 'OK' then
  245.    do
  246.       backup
  247.       if rc ~= 0 then
  248.          do
  249.             say "Backup failed.  Error code: " || rc
  250.             error /* Exit through error handler */
  251.          end
  252.       quit /* command to MRBackup to quit */
  253.    end
  254. else
  255.    error
  256. exit 0 /* end of program, success return code */
  257.  
  258. /*********************************************************************
  259. classifydate(date, weekday)
  260.  
  261. Function to decide if a date is the first of month or week
  262. *********************************************************************/
  263.  
  264. classifydate:
  265.  
  266. date    = arg(1)
  267. weekday = arg(2)
  268. parse var date day month year garbageintail
  269. select
  270.    when day = 1 then
  271.       datetype = 'newmonth'
  272.    when weekday = 'Sunday' then
  273.       datetype = 'newweek'
  274.    otherwise
  275.       datetype = 'daily'
  276. end
  277.  
  278. return datetype
  279.  
  280. /*********************************************************************
  281. setNewMonth(homepath, backuppath, lastFullBackup)
  282.  
  283.      Inputs:
  284.          homepath            String, filepath to be backed up
  285.          backuppath          String, filepath to be backed up
  286.          lastFullBackup      String, date in AmigaDOS format of
  287.                              last full backup
  288.  
  289.     Function to set MRBackup's parameter for monthly backup.
  290. Back up everything since last full backup.  Build "files since" date
  291. of last full backup, select df0:, quick format, ignore archive bits,
  292. and no compression.
  293. *********************************************************************/
  294. setNewMonth:
  295.  
  296. homepath    = arg(1)
  297. backuppath  = arg(2)
  298. lastBackup  = arg(3)
  299.  
  300. /**********************************************************
  301. The date to backup from is midnight of the date of the last
  302. full backup.
  303. **********************************************************/
  304.  
  305. parse var lastBackup weekday datestring timestring
  306.  
  307. /*** CUSTOMIZE ***/
  308. testdate    = datestring || " 00:00:00"
  309. compression = 'None'
  310. formatting  = 'Quick'
  311. testbits    = 'No'
  312. comment     = "Monthly backup: All files since date of full backup"
  313. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  314.            formatting, testdate, testbits)
  315.  
  316. return toReturn
  317.  
  318. /*********************************************************************
  319. setNewWeek(homepath, backuppath, date)
  320.  
  321.      Inputs:
  322.          homepath   String, filepath to be backed up
  323.          backuppath String, filepath to be backed up
  324.          date       String, current date in ARexx form
  325.                     (as opposed to AmigaDOS form)
  326.  
  327.     Function to set MRBackup's parameter for weekly backup.
  328. Back up everything since last monthly backup, = first day of the
  329. month in the input date.  Build "files since" date of the first of
  330. the month, select df0:, quick format, ignore archive bits,
  331. and no compression.
  332. *********************************************************************/
  333.  
  334. setNewWeek:
  335.  
  336. homepath   = arg(1)
  337. backuppath = arg(2)
  338. date       = arg(3)
  339.  
  340. /*************************************************
  341. Get the month, set new date to first day of month.
  342. Translate 19yy to yy, use midnight on the first.
  343. *************************************************/
  344. parse var date oldday month year rest
  345. yearpart = right(year, 2)
  346. testdate    = '01-' || month || '-' || yearpart || " 00:00:00"
  347.  
  348. /*** CUSTOMIZE ***/
  349. compression = 'None'
  350. formatting  = 'Quick'
  351. testbits    = 'No'
  352. comment     = "Weekly backup: All files since first of this month"
  353. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  354.                          formatting, testdate, testbits)
  355.  
  356. return toReturn
  357.  
  358. /*********************************************************************
  359. setNewDaily(homepath, backuppath, weekday)
  360.  
  361.      Inputs:
  362.          homepath   String, filepath to be backed up
  363.          backuppath String, filepath to be backed up
  364.          weekday    String, current day of the week
  365.  
  366.     Function to set MRBackup's parameters for daily backup.
  367. Back up everything that has archive bits clear, build a backup
  368. filename from the current weekday, no format, and 16-bit compression.
  369. *********************************************************************/
  370. setNewDaily:
  371.  
  372. homepath   = arg(1)
  373. backupdev  = arg(2)
  374. weekday    = arg(3)
  375.  
  376. /*** CUSTOMIZE ***/
  377. backuppath = backupdev || weekday || "/"
  378. testdate    = 'nil'
  379. compression = '16-Bit'
  380. formatting  = 'None'
  381. testbits    = 'Yes'
  382. comment     = "Daily backup: All files with archive bit clear"
  383. toReturn = setParameters(homepath, backuppath, comment, compression, ,
  384.    formatting, testdate, testbits)
  385.  
  386. return toReturn
  387.  
  388. /*********************************************************************
  389. setParameters(homepath, backuppath, comment, compression, formatting,
  390.               testdate, testbits)
  391.  
  392.      Inputs:
  393.         homepath   String, filepath to disk area to back up
  394.         backuppath String, filepath to disk to which the backup
  395.                    is to be saved
  396.         comment    String, to display in MRBackup's comment gadget.
  397.                    Informs user what type of backup is being done.
  398.         compression String, None or 16-Bit.
  399.         testdate   String, an AmigaDOS date or nil.  nil indicates
  400.                    the date is not tested.
  401.         testbits   String, YES or NO.  If archive bits are tested,
  402.                    testdate is not used.  If archive bits are not
  403.                    tested, testdate is used.
  404.  
  405.      Returns:
  406.         toReturn   String, OK or FAIL (conforms to the code returned
  407.                    by each MRBackup command).  Tells the caller if
  408.                    everything was set successfully.
  409.  
  410.      This function sends ARexx commands to MRBackup to set the
  411. parameters calculated by earlier functions.  It tests for successful
  412. completion of each ARexx message.
  413.  
  414.     Assume that standard parameters common to all types
  415. of backups (e.g. mode = AmigaDOS) are set in the usual
  416. MRBackup.init, which MRBackup loaded on startup.
  417. *********************************************************************/
  418.  
  419. setParameters:
  420. arg homepath, backuppath, comment, compression, formatting, testdate, ,
  421.     testbits
  422.  
  423. /*************************************************
  424. Check the backup disk is present before giving the
  425. setbackpath command.  If it's a device name,
  426. MRBackup checks it when it's time to begin writing
  427. to it.  If it contains a directory path,
  428. MRBackup requires that directory be available on
  429. a mounted device when the setbackpath command
  430. is issued.
  431. *************************************************/
  432. if right(backuppath, 1) ~= ':' then
  433.    do while ~exists(backuppath)
  434.       string = "'Please mount " || backuppath || " in any drive'"
  435.       'getchoice' '"'string'"' 'OK'
  436.    end
  437.  
  438. setfilemode "Replace"
  439.  
  440. /***************************
  441. This section sets all the
  442. MRBackup parameters.  The
  443. strategy is:
  444.  
  445.  set a parameter
  446.  as long as no error yet,
  447.     keep going to set more
  448.  
  449. Most of the ARexx commands
  450. put a return code, OK or
  451. FAIL, in the variable
  452. result.  Test result after
  453. each command, and keep going
  454. as long as it's OK.
  455.  
  456. Some of the commands put
  457. something else in result.
  458. For these, check the ARexx
  459. return variable rc.  Set
  460. result to indicate the same
  461. state that rc indicates.
  462. This keeps the current
  463. state consistent in result,
  464. and lets it be used
  465. consistently to test if
  466. the next parameter should
  467. be tested.
  468.  
  469. If any command returns
  470. a failure code, all of
  471. the remaining tests
  472. fall through, and no
  473. more commands are sent to
  474. MRBackup.
  475. ***************************/
  476.  
  477. if result ~= 'FAIL' then
  478.     setbackpath backuppath    /* returns result = OK or FAIL             */
  479. if result ~= 'FAIL' then
  480.    sethomepath homepath       /* returns result = current path, check rc */
  481. if rc ~= 0 then
  482.    do
  483.       result = 'FAIL'
  484.    end
  485. else
  486.    listing 'YES'                          /* returns result = OK or FAIL */
  487. if result ~= 'FAIL' then
  488.    setarcbits 'yes'    /* always set the bits after we finish backing up */
  489. if result ~= 'FAIL' then
  490.    'setinfogadget' '"'comment'"'          /* always returns result = OK  */
  491. if result = 'OK' then
  492.    'setcompression' '"'compression'"'     /* returns result = OK or FAIL */
  493. if result ~= 'FAIL' then
  494.    'setformatting' '"'formatting'"'    /* returns current mode, check rc */
  495. if rc ~= 0 then
  496.    do
  497.       result = 'FAIL'
  498.    end
  499. else
  500.    'testarcbits' '"'testbits'"' /* Set "test bits" to either Yes or No */
  501. if result ~= 'FAIL' then
  502.    do
  503.    /***********************************************
  504.    only test date if we aren't testing archive bits
  505.    ***********************************************/
  506.    if testbits = 'NO' then
  507.       do
  508.          'dateformat 0'
  509.          settestdate '"'testdate'"' /* returns current date, check rc */
  510.          if rc ~= 0 then result = 'FAIL'
  511.          else result = 'OK'
  512.       end
  513.    end
  514.  
  515. return result
  516.  
  517. /*********************************************************************
  518. error
  519.  
  520.      This function handles an error condition.  It exits with
  521. return code 6, which is 1 higher than a warning.  It sends a
  522. quit to MRBackup.
  523. *********************************************************************/
  524. error:
  525.  
  526. say "Exiting because of error"
  527. quit /* command to MRBackup to quit */
  528. exit 6
  529.  
  530. /*********************************************************************
  531. break_c
  532.  
  533.      This function exits the ARexx script on a user control-c
  534. interrupt.  It does not stop MRBackup.  It exits with return code
  535. 5, which is a warning.
  536. *********************************************************************/
  537. break_c:
  538.  
  539. say "*** Control-C recieved.  Stopped by user. ***"
  540. /* Note:  Do not command to MRBackup to quit.  Leave running, assume
  541. user needs to look at something.
  542. */
  543. exit 5
  544.